package com.hujing.springsource.a04;

import org.springframework.beans.PropertyValues;
import org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor;
import org.springframework.beans.factory.annotation.InjectionMetadata;
import org.springframework.beans.factory.config.DependencyDescriptor;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.annotation.ContextAnnotationAutowireCandidateResolver;
import org.springframework.core.MethodParameter;

import java.lang.reflect.Field;
import java.lang.reflect.Method;

/**
 * 该案例用来分析@Autowired注解的执行原理
 * 1.通过findAutowiringMetadata方法获取有@Autowired注解的属性或方法
 * 2.通过InjectionMetadata.inject方法将属性或方法注入到Bean1实例中
 */
public class DigInAutowired2 {

    public static void main(String[] args) throws Throwable {
        // GenericApplicationContext是一个干净的容器
        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
        beanFactory.registerSingleton("bean2",new Bean2());
        beanFactory.registerSingleton("bean3",new Bean3());
        Bean1 bean1 = new Bean1();
        
        //1.查找哪些属性,方法加了@Autowired注解
        AutowiredAnnotationBeanPostProcessor postProcessor = new AutowiredAnnotationBeanPostProcessor();
        beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());// 解析@Value注解
        postProcessor.setBeanFactory(beanFactory);
        // 利用反射获取findAutowiringMetadata方法
        Method method = AutowiredAnnotationBeanPostProcessor.class.getDeclaredMethod("findAutowiringMetadata", String.class, Class.class, PropertyValues.class);
        // 设置方法为可访问
        method.setAccessible(true);
        // 执行方法获取InjectionMetadata
        InjectionMetadata metadata = (InjectionMetadata) method.invoke(postProcessor, "bean1", Bean1.class, null);
        // 2.调用InjectionMetadata.inject方法将属性或方法注入到Bean1实例中
        metadata.inject(bean1,"bean1",null);
        System.out.println(bean1);
        
        //3.如何按类型查找值
        //3.1先找到属性
        Field field = Bean1.class.getDeclaredField("bean3");
        //3.2创建DependencyDescriptor
        DependencyDescriptor dd1 = new DependencyDescriptor(field, false);
        //3.3调用BeanFactory.doResolveDependency方法
        Object o = beanFactory.doResolveDependency(dd1, null, null, null);
        System.out.println(o);

        Method method1 = Bean1.class.getDeclaredMethod("setBean2", Bean2.class);
        DependencyDescriptor dd2 = new DependencyDescriptor(new MethodParameter(method1, 0),false);
        Object o1 = beanFactory.doResolveDependency(dd2, null, null, null);
        System.out.println(o1);

        Method method2 = Bean1.class.getDeclaredMethod("setHome", String.class);
        DependencyDescriptor dd3 = new DependencyDescriptor(new MethodParameter(method2, 0), false);
        Object o2 = beanFactory.doResolveDependency(dd3, null, null, null);
        System.out.println(o2);
    }
    
}
